//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.tuiofx.internal.gesture;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javafx.application.Platform;
import javafx.event.EventType;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.input.PickResult;
import javafx.scene.input.SwipeEvent;
import org.tuiofx.Configuration;
import org.tuiofx.internal.util.LogUtils;

public class SwipeGestureRecognizer extends GestureRecognizer {
    private static final double DISTANCE_THRESHOLD = 50.0;
    private static final double DEVIATION_THRESHOLD = 4.0;
    private final Map<Integer, TouchPointTracker> trackers;
    private TuioTouchPoint firstTouchPoint;
    private long gestureStartTime;
    private static double VELOCITY_THRESHOLD = 1.5;
    private long gestureDuration;

    public SwipeGestureRecognizer(Node targetNode, Configuration config) {
        super(targetNode, config);
        this.requiredNumberOfTouches = 1;
        this.maxNumberOfTouches = 1;
        this.trackers = new HashMap<>();
        this.gestureStartTime = 0L;
    }

    public void touchesBegan(TuioTouchPoint touchPoint) {
        if (this.getTargetNode() != null) {
            TouchPointTracker tracker;
            if (this.touchPointsCount == 1) {
                this.firstTouchPoint = touchPoint;
                tracker = new TouchPointTracker();
                tracker.start(touchPoint.getSceneX(), touchPoint.getSceneY());
                this.trackers.put(touchPoint.getSessionID(), tracker);
                this.gestureStartTime = System.nanoTime();
            } else {
                tracker = new TouchPointTracker();
                tracker.start(touchPoint.getSceneX(), touchPoint.getSceneY());
                this.trackers.put(touchPoint.getSessionID(), tracker);
            }

        }
    }

    public void touchesMove(TuioTouchPoint touchPoint) {
        if (this.getTargetNode() != null) {
            TouchPointTracker tracker = this.trackers.get(touchPoint.getSessionID());
            if (tracker == null) {
                LogUtils.debug("Error in swipe recognition: touch ID is unknown.");
            } else {
                tracker.update(touchPoint.getSceneX(), touchPoint.getSceneY());
            }
        }
    }

    public void touchesEnd(TuioTouchPoint touchPoint) {
        TouchPointTracker tracker = this.trackers.get(touchPoint.getSessionID());
        if (tracker == null) {
            LogUtils.debug("Error in swipe recognition: touch ID is unknown.");
        } else {
            tracker.end(touchPoint.getSceneX(), touchPoint.getSceneY());
            if (touchPoint.getSessionID().equals(this.firstTouchPoint.getSessionID())) {
                this.gestureDuration = (System.nanoTime() - this.gestureStartTime) / 1000000L;
            }

            if (this.touchPointsCount <= 0) {
                tracker = this.trackers.get(this.firstTouchPoint.getSessionID());
                double optimalGestureDistance = tracker.getOptimalDistance();
                double actualGestureDistance = tracker.getActualDistance();
                double deviation = Math.abs(optimalGestureDistance - actualGestureDistance);
                boolean horizontal = tracker.getOptimalDistanceX() > tracker.getOptimalDistanceY();
                double primaryDistance = horizontal ? tracker.getOptimalDistanceX() : tracker.getOptimalDistanceY();
                double secondaryDistance = horizontal ? tracker.getOptimalDistanceY() : tracker.getOptimalDistanceX();
                double primaryAbsLength = horizontal ? tracker.actDistanceX : tracker.actDistanceY;
                double var10000;
                if (horizontal) {
                    var10000 = tracker.actDistanceY;
                } else {
                    var10000 = tracker.actDistanceX;
                }

                if (secondaryDistance > primaryDistance * 0.72654) {
                    LogUtils.debug("too diagonal ");
                    this.trackers.clear();
                } else {
                    double velocity = primaryAbsLength / (double) this.gestureDuration;
                    if (!(deviation > DEVIATION_THRESHOLD) && !(velocity < VELOCITY_THRESHOLD) && !(actualGestureDistance <= DISTANCE_THRESHOLD)) {
                        EventType<SwipeEvent> swipeEventType;
                        if (horizontal) {
                            swipeEventType = tracker.getAbsoluteDistanceX() < 0.0 ? SwipeEvent.SWIPE_LEFT : SwipeEvent.SWIPE_RIGHT;
                        } else {
                            swipeEventType = tracker.getAbsoluteDistanceY() < 0.0 ? SwipeEvent.SWIPE_UP : SwipeEvent.SWIPE_DOWN;
                        }

                        if (swipeEventType != null) {
                            this.processSwipe(swipeEventType, this.trackers.size());
                        }

                        this.trackers.clear();
                    } else {
                        this.trackers.clear();
                    }
                }
            }
        }
    }

    private void processSwipe(final EventType<SwipeEvent> swipeEventType, final int touchCount) {
        final TuioTouchPoint target = this.firstTouchPoint;
        Platform.runLater(new Runnable() {
            public void run() {
                PickResult pickResult = new PickResult(target.getTargetNode(), target.getSceneX(), target.getSceneY());
                SwipeGestureRecognizer.this.fireEvent(target.getTargetNode(), new SwipeEvent(swipeEventType, target.getSceneX(), target.getSceneY(), target.getScreenX(), target.getScreenY(), false, false, false, false, true, touchCount, pickResult));
            }
        });
    }

    private Point2D computeSwipeCentroid() {
        float sumX = 0.0F;
        float sumY = 0.0F;

        TouchPointTracker tracker;
        for (Iterator<TouchPointTracker> var3 = this.trackers.values().iterator(); var3.hasNext(); sumY = (float) ((double) sumY + tracker.getCenter().getY())) {
            tracker = var3.next();
            sumX = (float) ((double) sumX + tracker.getCenter().getX());
        }

        int div = this.trackers.size();
        float focusX = sumX / (float) div;
        float focusY = sumY / (float) div;
        return new Point2D((double) focusX, (double) focusY);
    }

    private static class TouchPointTracker {
        private double beginX;
        private double beginY;
        private double lastX;
        private double lastY;
        private double optimalGestureDistance;
        private double actualGestureDistance;
        double actDistanceX;
        double actDistanceY;
        private double optDistanceX;
        private double optDistanceY;
        private double optAbsDistanceX;
        private double optAbsDistanceY;
        double maxDeviationX;
        double maxDeviationY;

        private TouchPointTracker() {
            this.actualGestureDistance = 0.0;
            this.actDistanceX = 0.0;
            this.actDistanceY = 0.0;
            this.optDistanceX = 0.0;
            this.optDistanceY = 0.0;
            this.optAbsDistanceX = 0.0;
            this.optAbsDistanceY = 0.0;
            this.maxDeviationX = 0.0;
            this.maxDeviationY = 0.0;
        }

        public void start(double sceneX, double sceneY) {
            this.beginX = sceneX;
            this.beginY = sceneY;
            this.lastX = sceneX;
            this.lastY = sceneY;
        }

        public void update(double sceneX, double sceneY) {
            double absLengthX = Math.abs(sceneX - this.lastX);
            double absLengthY = Math.abs(sceneY - this.lastY);
            this.actDistanceX += absLengthX;
            this.actDistanceY += absLengthY;
            double devX = Math.abs(sceneX - this.beginX);
            if (devX > this.maxDeviationX) {
                this.maxDeviationX = devX;
            }

            double devY = Math.abs(sceneY - this.beginY);
            if (devY > this.maxDeviationY) {
                this.maxDeviationY = devY;
            }

            this.actualGestureDistance += Math.hypot(absLengthX, absLengthY);
            this.lastX = sceneX;
            this.lastY = sceneY;
        }

        public void end(double sceneX, double sceneY) {
            this.update(sceneX, sceneY);
            this.lastX = sceneX;
            this.lastY = sceneY;
            this.optAbsDistanceX = this.lastX - this.beginX;
            this.optAbsDistanceY = this.lastY - this.beginY;
            this.optDistanceX = Math.abs(this.optAbsDistanceX);
            this.optDistanceY = Math.abs(this.optAbsDistanceY);
            this.optimalGestureDistance = Math.hypot(this.optDistanceX, this.optDistanceY);
        }

        public double getOptimalDistance() {
            return this.optimalGestureDistance;
        }

        public double getOptimalDistanceX() {
            return this.optDistanceX;
        }

        public double getOptimalDistanceY() {
            return this.optDistanceY;
        }

        public double getActualDistance() {
            return this.actualGestureDistance;
        }

        public double getAbsoluteDistanceX() {
            return this.optAbsDistanceX;
        }

        public double getAbsoluteDistanceY() {
            return this.optAbsDistanceY;
        }

        public double getActualDistanceX() {
            return this.actDistanceX;
        }

        public double getActualDistanceY() {
            return this.actDistanceY;
        }

        public Point2D getCenter() {
            double deltaX = this.lastX - this.beginX;
            double deltaY = this.lastY - this.beginY;
            double centerX = this.beginX + deltaX;
            double centerY = this.beginY + deltaY;
            return new Point2D(centerX, centerY);
        }
    }
}
